import { PERMISSION_KEY_DICT_TYPE, ShowModalTypeEnum } from '@/constants';
import {
  addDictType,
  deleteDictTypeById,
  getDictTypeById,
  getDictTypeList,
  updateDictType,
} from '@/services/system/dictType';
import { checkRespSuccessful } from '@/utils/serviceUtils';
import {
  ModalForm,
  ProDescriptions,
  ProDescriptionsItemProps,
  ProFormSelect,
  ProFormText,
} from '@ant-design/pro-components';
import { Access, useAccess, useModel, useRequest } from '@umijs/max';
import { Button, Drawer, Dropdown, Input, Modal, Tree, message, theme } from 'antd';
import { ItemType } from 'antd/es/menu/hooks/useItems';
import { DataNode } from 'antd/es/tree';
import React, {
  Key,
  useImperativeHandle,
  forwardRef,
  useState,
  useMemo,
  useEffect,
  useCallback,
} from 'react';

interface Props {
  onSelect?: (selectedKeys: React.Key[]) => void;
  selectedKeys?: Key[];
  style?: React.CSSProperties;
  fieldNames?: {
    title?: string;
    key?: string;
    children?: string;
  };
}

export type DictTypeTreeRefType = { refresh: () => void };

const searchParentKeys = (
  tree: API.DictTypeTreeNode[],
  searchValue: string,
  selectedKeys: React.Key[],
  parentId?: string,
  wrap: Set<React.Key> = new Set(),
): Set<React.Key> => {
  if (searchValue === '' && selectedKeys.length <= 0) {
    return wrap;
  }
  tree.forEach((item) => {
    if (
      parentId &&
      searchValue &&
      ((item.name && item.name?.indexOf(searchValue) !== -1) ||
        (item.type && selectedKeys.includes(item.type)))
    ) {
      wrap.add(parentId);
    }
    if (item.children) {
      searchParentKeys(item.children, searchValue, selectedKeys, item.type, wrap);
    }
  });

  return wrap;
};

const DictTypeTree = forwardRef<DictTypeTreeRefType, Props>(
  (
    {
      onSelect,
      selectedKeys: insertSelectedKeys,
      style,
      fieldNames = {
        title: 'label',
        key: 'type',
        children: 'children',
      },
    },
    ref,
  ) => {
    if (!fieldNames.key) {
      fieldNames.key = 'type';
    }
    if (!fieldNames.title) {
      fieldNames.title = 'label';
    }
    const { initialState } = useModel('@@initialState');
    // 权限控制
    const access = useAccess();
    const { data, error, refresh } = useRequest(getDictTypeList);
    const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
    const [searchValue, setSearchValue] = useState('');
    const [selectedKeys, setSelectedKeys] = useState<React.Key[]>(insertSelectedKeys || []);
    useEffect(() => {
      if (insertSelectedKeys) {
        setSelectedKeys(insertSelectedKeys);
      }
    }, [insertSelectedKeys]);
    const { useToken } = theme;
    const { token } = useToken();

    // 新建窗口的弹窗
    const [modalOpen, setModalOpen] = useState<boolean>(false);
    // 分布更新窗口的弹窗
    const [actionType, setActionType] = useState<ShowModalTypeEnum>(ShowModalTypeEnum.CREATE);
    // 展示详情的窗口
    const [showDetail, setShowDetail] = useState<boolean>(false);
    // 选中的当前行
    const [currentRow, setCurrentRow] = useState<API.DictType>();
    const [tableColumns, setTableColumns] = useState<PageType.CloumnType<API.DictType>[]>();
    useEffect(() => {
      setTableColumns([
        {
          title: '字典类型 ID',
          dataIndex: 'id',
          hideInTable: true,
          hideInSearch: true,
        },
        {
          title: '字典类型',
          dataIndex: 'type',
          showDetail: true,
          rules: [{ required: true }],
        },
        {
          title: '字典类型名称',
          dataIndex: 'name',
          ellipsis: true,
          rules: [{ required: true }],
        },
        {
          title: '状态',
          dataIndex: 'status',
          valueType: 'select',
          valueEnum: initialState?.system_common_status?.valueEnum,
          options: initialState?.system_common_status?.numOptions,
          rules: [{ required: true, message: '请选择状态' }],
        },
        {
          title: '备注',
          dataIndex: 'remark',
          hideInSearch: true,
          hideInTable: true,
        },
        {
          title: '创建时间',
          dataIndex: 'createTime',
          valueType: 'dateTime',
          hideInSearch: true,
          hideInModal: true,
        },
      ]);
    }, [initialState]);

    useImperativeHandle(
      ref,
      () => ({
        refresh: () => {
          refresh();
          setSearchValue('');
        },
      }),
      [refresh],
    );

    const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      const { value } = e.target;
      const newExpandedKeys = searchParentKeys(data || [], value, selectedKeys || [], 'all');
      setExpandedKeys(Array.from(newExpandedKeys));
      setSearchValue(value);
    };

    const handleAddOrUpdate = useCallback(async (item: API.DictType, flag: ShowModalTypeEnum) => {
      const tipText = flag === ShowModalTypeEnum.UPDATE ? '更新' : '添加';
      const hide = message.loading(`正在${tipText}字典类型信息`);

      try {
        let res: API.Resp = { success: false, message: `暂不支持${tipText}字典类型` };
        if (flag === ShowModalTypeEnum.UPDATE) {
          res = await updateDictType(item);
        } else if (flag === ShowModalTypeEnum.CREATE) {
          res = await addDictType(item);
        }

        hide();
        if (checkRespSuccessful(res)) {
          message.success(`${tipText}成功`);
          return true;
        } else {
          message.error(`${tipText}失败，后台响应：${res.message}，请重试`);
          return false;
        }
      } catch (error) {
        hide();
        message.error(`${tipText}失败，请重试`);
        return false;
      }
    }, []);

    const actionList: ItemType[] = [
      {
        key: 'showDetail',
        label: '查看详情',
      },
    ];

    if (
      PERMISSION_KEY_DICT_TYPE.update && PERMISSION_KEY_DICT_TYPE.update
        ? access.permissionFilter(PERMISSION_KEY_DICT_TYPE.update)
        : true
    ) {
      actionList.push({
        key: 'edit',
        label: '编辑',
      });
    }
    if (
      PERMISSION_KEY_DICT_TYPE.delete && PERMISSION_KEY_DICT_TYPE.delete
        ? access.permissionFilter(PERMISSION_KEY_DICT_TYPE.delete)
        : true
    ) {
      actionList.push({
        key: 'delete',
        label: '删除',
        danger: true,
      });
    }

    const treeData = useMemo(() => {
      const loop = (data: API.DictTypeTreeNode[]): API.DictTypeTreeNode[] =>
        data.map((item) => {
          const strTitle = item.name || '';
          const index = strTitle.indexOf(searchValue);
          const beforeStr = strTitle.substring(0, index);
          const afterStr = strTitle.slice(index + searchValue.length);
          const showValue =
            index > -1 ? (
              <span>
                {beforeStr}
                <span style={{ color: token.colorPrimary }}>{searchValue}</span>
                {afterStr}
              </span>
            ) : (
              <span>{strTitle}</span>
            );

          const label =
            item.type === 'all' ? (
              showValue
            ) : (
              <Dropdown
                trigger={['contextMenu']}
                menu={{
                  onClick: ({ key, domEvent }) => {
                    // 阻止事件冒泡
                    domEvent.stopPropagation();
                    switch (key) {
                      case 'delete':
                        Modal.confirm({
                          type: 'warn',
                          title: '是否删除',
                          content: `是否删除“${item.name}”`,
                          onOk: () => {
                            if (typeof item.id === 'undefined') {
                              console.error('拟删除的字典 value 为空', item.id);
                              return;
                            }
                            deleteDictTypeById(item.id)
                              .then((res) => {
                                if (!checkRespSuccessful(res)) {
                                  message.error(`删除字典类型失败，后台响应：${res.message}`);
                                  return;
                                }
                                message.success(`删除字典类型成功`);
                                setShowDetail(false);
                                const newSelectedKeys = selectedKeys.filter(
                                  (selectedKey) => selectedKey !== item.type,
                                );
                                setSelectedKeys(newSelectedKeys);
                                if (onSelect) {
                                  onSelect(newSelectedKeys);
                                }
                                refresh();
                              })
                              .catch((err) => {
                                message.error(`删除字典类型失败，后端系统异常`);
                                console.error(err);
                              });
                          },
                          okType: 'danger',
                          okText: '删除',
                        });
                        break;
                      case 'edit':
                        setActionType(ShowModalTypeEnum.UPDATE);
                        setCurrentRow(item);
                        setModalOpen(true);
                        break;
                      case 'showDetail':
                        setCurrentRow(item);
                        setShowDetail(true);
                        break;
                    }
                  },
                  items: actionList,
                }}
              >
                {showValue}
              </Dropdown>
            );

          if (item.children) {
            return {
              ...item,
              label: label as unknown as string,
              id: item.id,
              children: loop(item.children),
            };
          }

          return {
            ...item,
            label: label as unknown as string,
            id: item.id,
          };
        });
      return loop(
        data
          ? [
              {
                name: '全部类型',
                type: 'all',
                children: data,
              },
            ]
          : [],
      );
    }, [searchValue, data]);

    useEffect(() => {
      setExpandedKeys(treeData.map((item) => item.type || ''));
    }, [treeData]);

    if (error) {
      message.error(error.message);
      console.error('error', error);
    }

    return (
      <>
        <div style={style}>
          <Access
            accessible={
              PERMISSION_KEY_DICT_TYPE.add && PERMISSION_KEY_DICT_TYPE.add
                ? access.permissionFilter(PERMISSION_KEY_DICT_TYPE.add)
                : true
            }
          >
            <Button
              type="primary"
              block
              onClick={() => {
                setActionType(ShowModalTypeEnum.CREATE);
                setCurrentRow(undefined);
                setModalOpen(true);
              }}
            >
              新建字典类型
            </Button>
          </Access>

          <Input
            placeholder="搜索字典类型"
            value={searchValue}
            style={{
              marginTop: token.margin,
            }}
            onChange={onChange}
          />
          <Tree
            style={{
              marginTop: token.margin,
            }}
            fieldNames={fieldNames}
            expandAction={false}
            showIcon={false}
            treeData={treeData as unknown as DataNode[]}
            selectedKeys={selectedKeys}
            onSelect={(selectedKeysValue, info) => {
              const newSelectedKeys = [...selectedKeysValue];
              if (!newSelectedKeys.includes(info.node.key)) {
                newSelectedKeys.push(info.node.key);
              }
              setSelectedKeys(newSelectedKeys);
              if (onSelect) {
                onSelect(newSelectedKeys);
              }
            }}
            expandedKeys={expandedKeys}
            onExpand={(expandedKeysValue) => {
              setExpandedKeys(expandedKeysValue);
            }}
          />
        </div>
        {modalOpen && (
          <ModalForm
            title={`${actionType === ShowModalTypeEnum.CREATE ? '新建' : '编辑'}字典类型`}
            width={600}
            layout="horizontal"
            labelCol={{ span: 5 }}
            open={modalOpen}
            omitNil
            isKeyPressSubmit
            request={async () => {
              if (actionType === ShowModalTypeEnum.UPDATE && currentRow?.id) {
                const res = await getDictTypeById(currentRow?.id);
                if (checkRespSuccessful(res)) {
                  return res.data;
                } else {
                  return null;
                }
              }
              return { ...currentRow };
            }}
            onOpenChange={setModalOpen}
            onFinish={async (values) => {
              if (!values) {
                return;
              }
              if (actionType === ShowModalTypeEnum.CREATE) {
                delete values.id;
              }
              const success = await handleAddOrUpdate(values as API.DictType, actionType);
              if (success) {
                setCurrentRow(undefined);
                setModalOpen(false);
                refresh();
              }
            }}
          >
            <ProFormText hidden name="id" label="字典 ID" />
            <ProFormText name="type" label="字典类型" rules={[{ required: true }]} />
            <ProFormText name="name" label="字典类型名称" rules={[{ required: true }]} />
            <ProFormSelect
              name="status"
              label="状态"
              options={initialState?.system_common_status?.numOptions}
              valueEnum={initialState?.system_common_status?.valueEnum}
              rules={[{ required: true, message: '请选择状态' }]}
            />
            <ProFormText name="remark" label="备注" />
          </ModalForm>
        )}
        <Drawer
          width={600}
          open={showDetail}
          onClose={() => {
            setCurrentRow(undefined);
            setShowDetail(false);
          }}
          closable={false}
        >
          {currentRow && (
            <ProDescriptions<API.DictType>
              column={1}
              title={currentRow?.name || '详情'}
              request={async () => {
                if (typeof currentRow.id !== 'undefined') {
                  return getDictTypeById(currentRow.id);
                }
                return { data: { ...currentRow } };
              }}
              columns={tableColumns as ProDescriptionsItemProps<API.DictType>[]}
            />
          )}
        </Drawer>
      </>
    );
  },
);

export default DictTypeTree;
